package larrys.pomodoro.domain.service;

import java.util.Calendar;
import java.util.Date;

import larrys.pomodoro.domain.entity.Round;
import larrys.pomodoro.domain.exception.PomodoroException;
import larrys.pomodoro.domain.repository.RoundRepository;
import larrys.pomodoro.util.AssertUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class RoundService {

	private static Log logger = LogFactory.getLog(RoundService.class);

	private final static int DEFAULT_ROUND_DURATION = 25 * 60;

	@Autowired
	private RoundRepository roundRepo;

	@Transactional
	public Round openRound(long userId, long activityId) {
		AssertUtil.validId(userId);
		AssertUtil.validId(activityId);
		logger.debug("Trying to open Round with: PomodoroUser[id:" + userId
				+ "], Activity[activityId:" + activityId + "]");
		Round runningRound = roundRepo.getRunningRoundByUserId(userId);
		if (runningRound != null) {
			logger.debug("PomodoroUser[userId:"
					+ userId
					+ "], Activity[activityId:"
					+ activityId
					+ "] has running "
					+ runningRound
					+ ", returning the running round instead of create a new one");
			return runningRound;
		}
		Round newRound = new Round(0, userId, activityId, false);
		newRound.setDuration(DEFAULT_ROUND_DURATION);
		roundRepo.addRound(newRound);

		logger.debug("Returning new created:" + newRound);
		return newRound;
	}

	@Transactional
	public void startRound(long userId) {
		AssertUtil.validId(userId);
		logger.debug("Trying to start running round with PomodoroUser[id:"
				+ userId + "]");
		Round runningRound = roundRepo.getRunningRoundByUserId(userId);
		if (runningRound == null) {
			PomodoroException e = new PomodoroException();
			e.setExceptionCode("norunninground");
			throw e;
		}
		runningRound.setStartTime(new Date());
		roundRepo.updateRound(runningRound);
	}

	public Round getRunningRound(long userId) {
		AssertUtil.validId(userId);
		logger.debug("Trying to get running round with PomodoroUser[id:"
				+ userId + "]");
		Round runningRound = roundRepo.getRunningRoundByUserId(userId);
		logger.debug("Returning " + runningRound);
		return runningRound;
	}

	@Transactional
	public void finishRound(long roundId, boolean fullRound) {
		AssertUtil.validId(roundId);
		logger.debug("Trying to finish Round[id:" + roundId + "]");
		Round round = roundRepo.getRoundById(roundId);
		if (round == null) {
			return;
		}
		if (fullRound) {
			long durationInMillis = round.getDuration() * 1000;
			Calendar cal = Calendar.getInstance();
			cal.setTimeInMillis(round.getStartTime().getTime()
					+ durationInMillis);
			roundRepo.markRoundFinishedById(round.getId(), cal.getTime());
		} else {
			roundRepo.markRoundFinishedById(round.getId(), new Date());
		}
		logger.debug("Finished to finish " + round);
	}

	@Transactional
	public void interruptRound(long roundId) {
		AssertUtil.validId(roundId);
		logger.debug("Trying to interrupt Round[id:" + roundId + "]");
		roundRepo.markRoundInterruptedById(roundId, new Date());
		logger.debug("Finished to interrupt Round[id:" + roundId + "]");
	}

	@Transactional
	public void addRoundComment(long roundId, String comment) {
		AssertUtil.validId(roundId);
		logger.debug("Trying to add comment for Round[id:" + roundId
				+ ", comment: " + comment + "]");

		Round round = roundRepo.getRoundById(roundId);
		round.setComment(comment);

		roundRepo.updateRound(round);
		logger.debug("Finished to add comment for Round[id:" + roundId
				+ ", comment:" + comment + "]");
	}
}
